import _ from 'lodash';
import logger from '../../../common/logger';

import { eventBus } from '../eventBus';
import { AgentDto } from '../../model/agent/dtos';
import { AgentStatus } from '../../model/agent/type';
import { SimJobStatus } from '../../model/simulation/type';
import { IAgentService } from '../../model/agent/service';
import { SimulationJobDto } from '../../model/simulation/dtos';
import { JobAssignedEvent } from '../../event/jobAssigned';
import { ISimulationJobService } from '../../model/simulation/service';
import { AgentSelectionStrategy, AgentSelectionStrategyFactory } from './agentSelectionStrategy';
export class JobScheduleService {

  private agentService: IAgentService;
  private simulationJobService: ISimulationJobService;
  private scanInterval: number;

  constructor(jobService: ISimulationJobService, agentService: IAgentService, scanInterval: number = 5000) {
    this.simulationJobService = jobService;
    this.agentService = agentService;
    this.scanInterval = scanInterval;
  }

  init() {
    setInterval(()=>{
      this.processUnAssignedJobs();
    }, this.scanInterval);
  }

  async processUnAssignedJobs() {
    const jobs = await this.simulationJobService.findByStatus(SimJobStatus.Created);
    for (const job of jobs) {
      await this.schedule(job);
    }
  }

  async schedule(job: SimulationJobDto) {
    try {
      let agents: AgentDto[];
      if (_.isEmpty(job.agentId)) {
        agents = await this.agentService.findByProductAndStatus(job.product, AgentStatus.ONLINE);
      } else {
        const agentIds = job.agentId.split(';');
        agents = await this.agentService.findByIdentitiesAndStatus(agentIds, AgentStatus.ONLINE);
        // 如果用户选择的机器都已下线，自动选择在线的机器下发
        if (_.isEmpty(agents)) {
          agents = await this.agentService.findByProductAndStatus(job.product, AgentStatus.ONLINE);
        }
      }
      if (_.isEmpty(agents)) {
        logger.warn(`not found online agent for job(id=${job.id})`);
        return;
      }
      const strategy: AgentSelectionStrategy = AgentSelectionStrategyFactory.newSelectionStrategy(job.product);
      const agent = await strategy.select(agents);
      if (agent) {
        job.agentId = agent.identity;
        job.status = SimJobStatus.AgentAssigned;
        await this.simulationJobService.save(job);
        eventBus.emit(JobAssignedEvent.NAME, new JobAssignedEvent(job));
      }
    } catch (e) {
      logger.error(`schedule simulation job(id=${job.id}) error ${e.message} ${e.stack}`);
    }
  }
}



